﻿using System;
using System.Collections.Generic;
using System.Dynamic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace CSharpChapters_4
{
    class Program
    {
        static void Main(string[] args)
        {
            /***
             * 非指针类型到 dynamic 类型存在隐式类型转换
             * 通常都是在执行期才完成绑定的
             * 表达式编译时的类型也是 dynamic
             **/
            dynamic text = "hello world";
            string world = text.Substring(6);
            Console.WriteLine(world);
            //执行期间抛出异常
            //string broken = text.SUBSTR(6);
            //Console.WriteLine(broken);

            //动态类型的加法操作
            Add("text");
            Add(10);
            Add(TimeSpan.FromMinutes(45));

            //动态方法重载决议
            CallMethod(10);
            CallMethod(10.5m);
            CallMethod(10L);
            CallMethod("text");

            //ExpandoObject：一个装有数据和方法的动态袋子
            dynamic expando = new ExpandoObject();
            //将数据赋值给属性
            expando.SomeData = "Some data";
            //将委托赋值给属性
            Action<string> action = input => Console.WriteLine("The input was '{0}'", input);
            expando.FakeMethod = action;

            //动态访问数据和委托
            Console.WriteLine(expando.SomeData);
            expando.FakeMethod("hello");

            //将expandobject 视作字典并打印
            IDictionary<string, object> dictionary = expando;
            Console.WriteLine("Keys:{0}", string.Join(",", dictionary.Keys));

            //使用静态上下文填充数据， 然后从动态值获取数据
            dictionary["otherData"] = "other";
            Console.WriteLine(expando.otherData);

            //编译不可通过
            //IList<T>有 Add 这样的方法，接收 T 型值作为输入。这个类型的变体具有潜在的危险
            //IList<string> strings = new List<string> { "a", "b", "c" };
            //IList<object> objects = strings;

            //编译可通过
            //IEnumerable<string> strings = new List<string> { "a", "b", "c" };
            //IEnumerable<object> objects = strings;

            /*
             *  用 out 修饰的类型形参是协变的。
           *  用 in 修饰的类型形参是逆变的。
           *  没有修饰符的类型形参是不变的。
             * */
            Action<object> objs = obj => Console.WriteLine(obj);
            Action<string> strs = objs;
            strs("print me");
        }
        #region 动态类型的加法操作
        static void Add(dynamic d)
        {
            Console.WriteLine(d + d);
        }
        #endregion


        #region 动态方法重载决议
        static void SampleMethod(int value)
        {
            Console.WriteLine("Method with int parameter");
        }
        static void SampleMethod(decimal value)
        {
            Console.WriteLine("Method with decimal parameter");
        }
        static void SampleMethod(object value)
        {
            Console.WriteLine("Method with object parameter");
        }
        static void CallMethod(dynamic d)
        {
            SampleMethod(d);
        }
        #endregion
    }
}
